/* 
 * File:   SendReceiveCommand.cpp
 * Author: Bram
 * 
 * Created on January 23, 2013, 7:29 PM
 */

#include "SendReceiveCommand.h"
#include "Config.h"



SendReceiveCommand::SendReceiveCommand(const char* szID )
	: Command( szID )
{
}

SendReceiveCommand::SendReceiveCommand() : Command() {
}

SendReceiveCommand::SendReceiveCommand(const SendReceiveCommand& orig) {
}

SendReceiveCommand::~SendReceiveCommand() {
}

bool SendReceiveCommand::isValid()
{
    return ((sizeParameters() > 0) && Command::isValid());
}

void SendReceiveCommand::SendFile(TcpSocket* clientORserver, queue<Command *>& commandQueue)
{
    string strEMPTY = "";
    string fileName;
    string strFileSize;
    unsigned long intFileSize = -1;
    string strSubDirOnServer;
    string basePath;
    string fullFilePath;
    string pathSEP = Config::getInstance()->PathSeparator;
    string errMSG;
    Config::getInstance()->getFullBasePath(basePath);
    
    getParameterAtIndex(0,fileName);
    getParameterAtIndex(1,strSubDirOnServer);
    
    stringstream ss;
    ss << basePath << pathSEP << fileName;
    fullFilePath = ss.str();
    
    fileName = Utility::getInstance()->FullFilePathToFileName(fullFilePath);
    
    Command * putCmdFILE = Clone();
    if(Utility::getInstance()->fileExists(fullFilePath)){
        std::ifstream infile;
        infile.open(fullFilePath.c_str(),std::ios::binary);
        //infile.open(fullFilePath.c_str(), std::ios::in | std::ios::binary);
        if (infile.fail() == 1)
        {
            putCmdFILE->clearParameters();
            putCmdFILE->setName("ERROR");
            putCmdFILE->addParameter("FAILLED TO OPEN FILE ON RECEIVE COMMAND!");
            
            string totalCommandStr = putCmdFILE->buildFullCommand();
            clientORserver->sendMessage(totalCommandStr);
        } else {
            struct stat FileInfo;
            
            if (stat(fullFilePath.c_str(), &FileInfo) == 0)
            {
                intFileSize = FileInfo.st_size;
                strFileSize = Utility::getInstance()->convertInt(intFileSize);
            }
            putCmdFILE->clearParameters();
            putCmdFILE->addParameter(fileName);
            putCmdFILE->addParameter(strFileSize);
            putCmdFILE->addParameter(strSubDirOnServer);
            putCmdFILE->addParameter("");
            putCmdFILE->addParameter("");
            
            string totalStartCMDstart = putCmdFILE->buildFullCommand();
            clientORserver->sendMessage(totalStartCMDstart);
            
            if(intFileSize > 0) { //als de file wel groter dan 1 byte is!
                //we schakelen naar het busy type!
                putCmdFILE->setType("BUSY");

                /* set cursor to the beginning of the file */
                infile.seekg(0, std::ios::beg);

                /* Since we are copying a file over the network we need to use a small buffer */
                int bufferSize = (intFileSize < 512) ? intFileSize : 512;

                int counter = 0;
                unsigned long size = intFileSize;

                char buf[bufferSize];

                while (!infile.eof())
                //while(size > 0)
                {
                    infile.read (buf, bufferSize);
                    string strEncodedToSend;
                    if(size < bufferSize){
                        char newBuf[size];
                        memcpy(newBuf, buf, size);

                        strEncodedToSend = (base64_encode(reinterpret_cast<const unsigned char*>(newBuf), sizeof(newBuf)));
                    } else {

                        strEncodedToSend = (base64_encode(reinterpret_cast<const unsigned char*>(buf), sizeof(buf)));
                    }
                    putCmdFILE->replaceParameterAtIndex(4,strEncodedToSend); //vervangt de 5e plek van het send commando!

                    //verstuurt het tussen busy commando
                    string totalStartCMDbusy = putCmdFILE->buildFullCommand();
                    clientORserver->sendMessage(totalStartCMDbusy);
                    counter++;
                    size -= bufferSize;
                }
            }
            
            infile.close();
            
            
            putCmdFILE->setType("END");
            string strOK = "OK";
            putCmdFILE->replaceParameterAtIndex(3,strOK);
            putCmdFILE->replaceParameterAtIndex(4,strEMPTY); //vervangt de 5e plek van het send commando!
            
            string totalStartCMDend = putCmdFILE->buildFullCommand();
            clientORserver->sendMessage(totalStartCMDend);
            
            cout << "**** END " << putCmdFILE->getName() << " COMMAND - SUCCESSFULLY SEND FILE: '" << fileName << "'!" << endl;
            dasLog << "**** END " <<  putCmdFILE->getName() << " COMMAND - SUCCESSFULLY SEND FILE: '" << fileName << "'!" << endl;
           //receivedCMD->PrintFullCout(); //debug!
        }
        
        
    } else {
        putCmdFILE->clearParameters();
        putCmdFILE->setName("ERROR");
        putCmdFILE->addParameter("FAILLED TO OPEN FILE, FILE NOT EXISTS!");

        string totalCommandStr = putCmdFILE->buildFullCommand();
        clientORserver->sendMessage(totalCommandStr);
    }
    putCmdFILE = 0;
    delete putCmdFILE;
}

void SendReceiveCommand::ReceiveFile(TcpSocket* clientORserver, queue<Command *>& commandQueue)
{
    bool breakReceivingFile = false;
    bool hasReceivedStartCommand = false;
    
    string fileName = "";
    string fullOutFilePath = "";
    string fullOutFileDir = "";
    string subDir = "";
    string basePath = "";
    string pathSEP = "";
    int fileSize = -1;
    
    ofstream outFile;
    
    while(!breakReceivingFile) {
        
    //haalt het volgende bericht op!
    Command * receivedCMD = getNextCommandFromSocket(clientORserver);
    //als het GEEN error is
    if((receivedCMD != 0) &&  !(receivedCMD->getName().compare("ERROR") == 0) ){ //als het geen error is
        //als het commando gelijk is aan het huidige commando!
        if(receivedCMD->getName().compare(getName()) == 0){
            if(receivedCMD->sizeParameters() > 4) { //put command parameter size is altijd 5!
               //cout << "****START '" << receivedCMD->getName() << "' COMMAND****" << endl;
                //dasLog << "****START '" << receivedCMD->getName() << "' COMMAND ****" << endl;
                if(receivedCMD->getType().compare("START") == 0) {
                    string strFileSize;
                    receivedCMD->getParameterAtIndex(0,fileName);
                    receivedCMD->getParameterAtIndex(1,strFileSize);
                    receivedCMD->getParameterAtIndex(2,subDir);
                    Utility::getInstance()->trim(subDir);
                    Utility::getInstance()->fixPathLinuxWindowsProblem(subDir,false);
                    
                    fileSize = atoi(strFileSize.c_str());
                    
                    Config::getInstance()->getFullBasePath(basePath);
                    pathSEP = Config::getInstance()->PathSeparator;
                    
                    stringstream ss;
                    ss << basePath;
                    if(subDir.size() > 0){
                        ss << pathSEP << subDir << pathSEP;
                    }
                    fullOutFileDir = ss.str();
                    ss << fileName;
                    fullOutFilePath = ss.str();
                    
                    Utility::getInstance()->createDir(fullOutFileDir, basePath);
                    
                    outFile.open(fullOutFilePath.c_str(), std::ios::binary); //maakt de file aan!
                    
                    hasReceivedStartCommand = true;
                } else if((receivedCMD->getType().compare("BUSY") == 0) && hasReceivedStartCommand ) {
                    string base6Data;
                    receivedCMD->getParameterAtIndex(4,base6Data);
                    string base64DecodedData = base64_decode(base6Data);
                    
                    int endPOS = outFile.tellp();
                    outFile.seekp(endPOS);
                    //outFile.seekp(ios::end);
                    outFile.write(base64DecodedData.c_str(), base64DecodedData.size()); //klapt de decoded data achter aan de file
                    
                } else if((receivedCMD->getType().compare("END") == 0) && hasReceivedStartCommand ) {
                    //@TODO misschien nog een check of de file volledig en goed ontvangen is!
                    cout << "**** END " << receivedCMD->getName() << " COMMAND - SUCCESSFULLY RECEIVED FILE: '" << fileName << "'!" << endl;
                    dasLog << "**** END " <<  receivedCMD->getName() << " COMMAND - SUCCESSFULLY RECEIVED FILE: '" << fileName << "'!" << endl;
                    //receivedCMD->PrintFullCout(); //debug!
                    breakReceivingFile = true;
                } else {
                    cout << receivedCMD->getName() << " COMMAND FAILLED!! - TYPE WRONG type=(" << receivedCMD->getType() << ")! or hasReceivedStartCommand: " << Utility::getInstance()->BoolToString(hasReceivedStartCommand) << endl;
                    dasLog << receivedCMD->getName() << " COMMAND FAILLED!! - TYPE WRONG type=(" << receivedCMD->getType() << ")! or hasReceivedStartCommand: " << Utility::getInstance()->BoolToString(hasReceivedStartCommand) << endl;
                    receivedCMD->PrintFullCout(); //debug!
                    breakReceivingFile = true;
                }
                
            } else {
                cout << receivedCMD->getName() << " COMMAND FAILLED!!" << endl;
                dasLog << receivedCMD->getName() << " COMMAND FAILLED!!" << endl;
                receivedCMD->PrintFullCout(); //debug!
                breakReceivingFile = true;
            }
        } else{
            cout << "ERROR in '" << __FILE__ << "' - '" << __FUNCTION__  << "()', curr cmd: '" << getName() << "', received cmd: '" << receivedCMD->getName() << "' - should not ever happen! 88886" << endl;
            dasLog << "ERROR in '" << __FILE__ << "' - '" << __FUNCTION__  << "()', curr cmd: '" << getName() << "', received cmd: '" << receivedCMD->getName() << "' - should not ever happen! 88886" << endl;
            breakReceivingFile = true;
        }
    } else { //error
        stringstream ssERROR;
        for(int i = 0; i < receivedCMD->sizeParameters(); i++){
            string strErr;
            receivedCMD->getParameterAtIndex(0,strErr);
            ssERROR << strErr << " - ";
        }
        string strTotalErr = ssERROR.str();
        //cout << receivedCMD->getName() << " COMMAND FAILLED! received error: " << strTotalErr << endl;
        //dasLog << receivedCMD->getName() << " COMMAND FAILLED! received error: " << strTotalErr << endl;
        breakReceivingFile = true;
    }
    
    
    receivedCMD = 0;
    delete receivedCMD;
    
    } // end while loop
    
    //als we er mee gaan kappe moet ie de outFile closen!
    if(breakReceivingFile){
        outFile.close();
    }
    
}